package spreadsheet;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jdom2.output.XMLOutputter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author Ahmed Saliem
 * This class represents a spreadsheet structure which has a 2D-Array of 
 * Spread Sheet Cells.
 * the main functionalities of this class is to save and load the spread sheet. 
 *
 */
public class SpreadSheet {
	
	/**
	 * cells is a 2d-array that represents the cells objects.
	 */
	private SpreadSheetCell[][] cells;
	/**
	 * default number of rows and columns.
	 */
	public static int NUMBER_OF_ROWS = 10;//1..10
	public static int NUMBER_OF_COLUMNS = 11; //A..K
	
	/**
	 * default Constructor
	 * that initializes the spread sheet cells to  NUMBER_OF_ROWS x NUMBER_OF_COLUMNS
	 * and gives each cell a default type and value.
	 */
	public SpreadSheet()
	{
		cells = new SpreadSheetCell[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
		initializeCells();
	}
	
	/**
	 *  create the cells and initialize each to 0.0 
	 */
	public void initializeCells()
	{
		for(int i=0;i<NUMBER_OF_ROWS;i++)
			for(int j=0;j<NUMBER_OF_COLUMNS;j++)
				cells[i][j] = new SpreadSheetCell();								
	}	
	
	/**
	 * 
	 * @param path : the path to save on.
	 * @return true if the save is successful and false otherwise.
	 * this method save the array of object into a XML file. 
	 */
	public boolean saveSpreadSheet(String path) throws FileNotFoundException, IOException
	{				
		if(path != null && path.length()>0){// check if the path is not null or empty.		
			
				 return xmlWriter(path);		        	
		}else{
			return false;
                }
		}
	
	public boolean xmlWritter(String path)
	{
		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder;
        try {
            dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.newDocument();
            //add elements to Document
            Element rootElement =
                doc.createElementNS(null, "SpreadSheetCells");
            //append root element to document
            doc.appendChild(rootElement);
            
            for (int i = 0; i < cells.length; i++) {
                for (int j = 0; j < cells[i].length; j++) {
                    //append new child element to root element and add attributes row and col.
                    if( cells[i][j] != null ) {
                        rootElement.appendChild(XMLWriterDOM.getCell(
                                doc, String.valueOf(i), String.valueOf(j), cells[i][j].getCellType(), cells[i][j].getCellValue()));
                    }
                }
            }
    				 
             
            //for output to file, console
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            //for pretty print
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(doc);
 
            //write to console or file
            StreamResult console = new StreamResult(System.out); 
            StreamResult file = new StreamResult(new File(path));
 
            //write data
            transformer.transform(source, console); // to be removed.
            transformer.transform(source, file);            
            System.out.println("DONE");
            return true;
 
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }        
	}
        
        public boolean xmlWriter( String path ) throws FileNotFoundException, IOException {
            org.jdom2.Element root = new org.jdom2.Element( "SpreadSheetCells" );
            org.jdom2.Document doc = new org.jdom2.Document( root );
            for( int i = 0; i < cells.length; i++ ) {
                for( int j = 0; j < cells[i].length; j++ ) {
                    if( cells[i][j] != null ) {
                        org.jdom2.Element elem = new org.jdom2.Element( "SpreadSheetCell" );
                        elem.setAttribute( "CellRow", i + "" );
                        elem.setAttribute( "CellCol", j + "" );
                        org.jdom2.Element elemCellType = new org.jdom2.Element( "CellType" );
                        elemCellType.setText( cells[i][j].getCellType() );
                        org.jdom2.Element elemCellValue = new org.jdom2.Element( "CellValue" );
                        elemCellValue.setText( cells[i][j].getCellValue() );
                        elem.setContent( elemCellType );
                        elem.addContent( elemCellValue );
                        root.addContent( elem );
                    }
                }
            }
            XMLOutputter serializer = new XMLOutputter();
            serializer.output( doc, new FileOutputStream( path ) );
            return true;
        }
	
	
	/**
	 * 
	 * @param path : the path to load from.
	 * @return true if the load is successful and false otherwise.
	 * this method load the a XML file into an array of objects. 
	 */
	public boolean loadSpreadSheet(String path)
	{
		if(path != null && path.length() > 0){ // check if the path is not null or empty.
		
			  return JDOMXMLReader.readXmlFile(path,cells);			          
			  
		}else{
			return false;
		}       
	}
	
	
	// for testing purposes.
	public void printSpreadSheet()
	{
		for(int i=0;i<NUMBER_OF_ROWS;i++)
		{
			for(int j=0;j<NUMBER_OF_COLUMNS;j++)			
				System.out.print("[" + cells[i][j]+"],");
			System.out.println();
		}
			
		
	}

	/**
	 * 
	 * getters and setters
	 */
	public SpreadSheetCell[][] getCells() {
		return cells;
	}

	public void setCells(SpreadSheetCell[][] cells) {
		this.cells = cells;
                NUMBER_OF_ROWS = cells.length;
                NUMBER_OF_COLUMNS = cells[0].length;
	}
        
        public void setCell( SpreadSheetCell cell, int row, int col ) {
            cells[row][col] = cell;
        }
}
